/*
 * This file is part of Cadmium.
 * Copyright (C) 2007-2010 Xavier Clerc.
 *
 * Cadmium is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Cadmium is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package fr.x9c.cadmium.support.scripting;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;

import fr.x9c.cadmium.Infos;

/**
 * This class implements the factory for OCaml scripting.
 *
 * @author <a href="mailto:cadmium@x9c.fr">Xavier Clerc</a>
 * @version 1.3
 * @since 1.1
 */
public final class OCamlScriptEngineFactory implements ScriptEngineFactory {

    /** Engine name. */
    private static final String ENGINE_NAME = "Cadmium";

    /** Engine version. */
    private static final String ENGINE_VERSION = Infos.VERSION;

    /** Engine extensions for source files. */
    private static final List<String> ENGINE_EXTENSIONS =
        Collections.unmodifiableList(Arrays.asList(new String[] {
                                                       "ml",
                                                       "mli"
                                                   }));

    /** Engine mime types for source files. */
    private static final List<String> ENGINE_MIME_TYPES =
        Collections.unmodifiableList(Arrays.asList(new String[] {
                                                       "text/plain",
                                                       "text/x-ocaml"
                                                   }));

    /** Engine names used for instance retrieval. */
    private static final List<String> ENGINE_NAMES =
        Collections.unmodifiableList(Arrays.asList(new String[] {
                                                       "Objective Caml",
                                                       "OCaml",
                                                       "ocaml"
                                                   }));

    /** Language (full) name. */
    private static final String LANGUAGE_NAME = "Objective Caml";

    /** Language (short) name. */
    private static final String LANGUAGE_SHORT_NAME = "OCaml";

    /** Language version. */
    private static final String LANGUAGE_VERSION = Infos.OCAML_VERSION;

    /** Engine parameters. */
    private static final Map<String, Object> PARAMETERS =
        new HashMap<String, Object>();

    /**
     * Parameters initialization.
     */
    static {
        final Map<String, Object> params = OCamlScriptEngineFactory.PARAMETERS;
        params.put(ScriptEngine.ENGINE,
                   OCamlScriptEngineFactory.ENGINE_NAME);
        params.put(ScriptEngine.ENGINE_VERSION,
                   OCamlScriptEngineFactory.ENGINE_VERSION);
        params.put(ScriptEngine.NAME,
                   OCamlScriptEngineFactory.LANGUAGE_SHORT_NAME);
        params.put(ScriptEngine.LANGUAGE,
                   OCamlScriptEngineFactory.LANGUAGE_NAME);
        params.put(ScriptEngine.LANGUAGE_VERSION,
                   OCamlScriptEngineFactory.LANGUAGE_VERSION);
        params.put("THREADING", "THREAD-ISOLATED");
    } // end static block

    /**
     * Constructs a script engine factory.
     */
    public OCamlScriptEngineFactory() {
    } // end empty constructor

    /**
     * {@inheritDoc}
     */
    @Override
    public String getEngineName() {
        return OCamlScriptEngineFactory.ENGINE_NAME;
    } // end method 'getEngineName()'

    /**
     * {@inheritDoc}
     */
    @Override
    public String getEngineVersion() {
        return OCamlScriptEngineFactory.ENGINE_VERSION;
    } // end method 'getEngineVersion()'

    /**
     * {@inheritDoc}
     */
    @Override
    public List<String> getExtensions() {
        return OCamlScriptEngineFactory.ENGINE_EXTENSIONS;
    } // end method 'getExtensions()'

    /**
     * {@inheritDoc}
     */
    @Override
    public String getLanguageName() {
        return OCamlScriptEngineFactory.LANGUAGE_NAME;
    } // end method 'getLanguageName()'

    /**
     * {@inheritDoc}
     */
    @Override
    public String getLanguageVersion() {
        return OCamlScriptEngineFactory.LANGUAGE_VERSION;
    } // end method 'getLanguageVersion()'

    /**
     * {@inheritDoc}
     */
    @Override
    public String getMethodCallSyntax(final String obj,
                                      final String m,
                                      final String... args) {
        final StringBuffer res = new StringBuffer();
        res.append(obj);
        res.append('#');
        res.append(m);
        for (String a : args) {
            res.append(' ');
            res.append(a);
        } // end for
        return res.toString();
    } // end method 'getMethodCallSyntax(String, String, String...)'

    /**
     * {@inheritDoc}
     */
    @Override
    public List<String> getMimeTypes() {
        return OCamlScriptEngineFactory.ENGINE_MIME_TYPES;
    } // end method 'getMimeTypes()'

    /**
     * {@inheritDoc}
     */
    @Override
    public List<String> getNames() {
        return OCamlScriptEngineFactory.ENGINE_NAMES;
    } // end method 'getNames()'

    /**
     * {@inheritDoc}
     */
    @Override
    public String getOutputStatement(final String toDisplay) {
        final StringBuffer res = new StringBuffer();
        res.append("print_string ");
        res.append(toDisplay);
        return res.toString();
    } // end method 'getOutputStatement(String)'

    /**
     * {@inheritDoc}
     */
    @Override
    public Object getParameter(final String key) {
        return OCamlScriptEngineFactory.PARAMETERS.get(key);
    } // end method 'getParameter(String)'

    /**
     * {@inheritDoc}
     */
    @Override
    public String getProgram(final String... statements) {
        final StringBuffer res = new StringBuffer();
        for (String s : statements) {
            res.append(s);
            res.append(";\n");
        } // end for
        return res.toString();
    } // end method 'getProgram(String...)'

    /**
     * {@inheritDoc}
     */
    @Override
    public ScriptEngine getScriptEngine() {
        return new OCamlScriptEngine();
    } // end method 'getScriptEngine()'

} // end class 'OCamlScriptEngineFactory'
